import std.stdio: writefln;
import std.string: toStringz;
import derelict.sdl.sdl;

import std.math;

import Point;
import Pixels;
import Lines;
import Circles;

import Graph;


const int   xResolution     = 800;
const int   yResolution     = 600;
const int   bitsPerPixel    = 32;

uint background;

SDL_Surface *screen;
Graph graph;
bool addingVert = true;
bool edgeBegin = true;
int eb;

void init() {
    DerelictSDL.load();

    // initialize SDL's VIDEO module
    SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);
	SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
    screen = SDL_SetVideoMode(xResolution, yResolution, bitsPerPixel, SDL_SWSURFACE );
    SDL_WM_SetCaption(toStringz("zad4"), null);
	setBackground(screen, 0x000000);
}

void setBackground(SDL_Surface *surface, uint color){
	uint *pos = cast(uint*)(surface.pixels);
	background = color;
	pos[0..xResolution*yResolution] = color;
	SDL_UpdateRect(screen,0,0,0,0);
}


// be nice and release all resources
void cleanup() {
    SDL_Quit();
    DerelictSDL.unload();
}

void keyDown(SDL_KeyboardEvent e){
    if(e.keysym.sym == SDLK_ESCAPE) throw new Exception("KungFuDeathGrip");
	if(e.keysym.sym == SDLK_q) {
		addingVert = false;
		graph.allocAM();
	}
	if(e.keysym.sym == SDLK_z)
		graph.train();
	if(e.keysym.sym == SDLK_p)
		graph.debugInfo();
/+	if(e.keysym.sym == SDLK_RIGHT) images.getNext(imageIn);
	if(e.keysym.sym == SDLK_LEFT) images.getPrevious(imageIn);
	if(e.keysym.sym == SDLK_a) images.addFromBox(imageIn);
	if(e.keysym.sym == SDLK_x) perceptrons.detect(imageIn, imageOut);+/
}

void drawFrame(){
	foreach(int i, vert;graph.vertices)
		if(graph.neurons){
			if(graph.neurons[i].sigma == -1)
				circle(screen, vert.x, vert.y, 10, 0xFF0000);
			else if(graph.neurons[i].sigma == 1)
				circle(screen, vert.x, vert.y, 10, 0x00FF00);
		}
		else{
			circle(screen, vert.x, vert.y, 10, 0x0000FF);
		}
	for(int i = 0; i < graph.adjacencyMatrix.length; i++)
		for(int j = 0; j < graph.vertices.length; j++)
			if(graph.adjacencyMatrix[i][j] != 0.0f)
				line(screen,	point(graph.vertices[i].x, graph.vertices[i].y),
								point(graph.vertices[j].x, graph.vertices[j].y),
								0x00FFFF);
	
}

void refresh(){
	SDL_UpdateRect(screen,0,0,0,0);
}

private void clearScreen(SDL_Surface *surface){
	uint *p = cast(uint *)surface.pixels;
	p[0..surface.w * surface.h] = background;
}

void mouseButtonUp(SDL_MouseButtonEvent e){
//    imageIn.keyUp(e.button);
}

void mouseButtonDown(SDL_MouseButtonEvent e){
//    imageIn.keyDown(e.button);
	if(addingVert)
		graph.addVertex(e.x, e.y);
	else{
		if(edgeBegin){
			eb = graph.getNearest(e.x, e.y, 10.f);
			writefln(eb);
			edgeBegin = false;
		}
		else{
			int ee = graph.getNearest(e.x, e.y, 10.f);
			writefln("\t", ee);
			graph.addEdge(eb, ee);
			edgeBegin = true;
		}
	}
}

void mouseMotion(SDL_MouseMotionEvent e){
/+    if ((e.x > (inputWindowX - 1) && e.x < (inputWindowX + imageIOWidth * scale )) &&
		(e.y > (inputWindowY - 1) && e.y < (inputWindowY + imageIOHeight* scale ))) {
        imageIn.mouseMotion(e.x - inputWindowX, e.y - inputWindowY);
    }+/
}


void main() {
	uint startTime;
	long frames;
	graph = new Graph();

    init();
//	writefln(SDL_MUSTLOCK(screen));
    scope(exit){
		writefln("\n Exiting.. \n %2.2f FPS\n",(cast(float)(frames)/(SDL_GetTicks()-startTime))*1000.f);
		cleanup();      // when we exit, perform cleanup
	}

	startTime = SDL_GetTicks();
    mainLoop:
    while (true) {
        SDL_Event event;

        // handle all SDL events that we might've received in this loop iteration
        while (SDL_PollEvent(&event)) {
            switch (event.type) {
                // user has clicked on the window's close button
                case SDL_QUIT:
                    break mainLoop;
				case SDL_KEYDOWN:
					keyDown(event.key);
					break;
				case SDL_MOUSEBUTTONDOWN:
					mouseButtonDown(event.button);
					break;
				case SDL_MOUSEBUTTONUP:
					mouseButtonUp(event.button);
					break;
				case SDL_MOUSEMOTION:
					mouseMotion(event.motion);
					break;
                // by default, we do nothing => break from the switch
                default:
                    break;
            }
        }
	
	SDL_LockSurface(screen);
	clearScreen(screen);
	drawFrame();
	SDL_UnlockSurface(screen);
	refresh();
//	SDL_UpdateRect(screen,0,0,0,0);
//	SDL_Flip(screen);
	frames++;
    }
}
